﻿
using ProjScan.Modules;
using ProjScan.RecordManager.AssetData;
using ProjScan.Tools;
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;

namespace ProjScan.Submodules.Effects_Play_Check
{
    internal class EffectPerformanceMonitor
    {
        private GameObject gameObject;

        private ParticleSystemDrawer particleSystemDrawer;

        private OverdrawMonitor overdrawMonitor;

        private ParticleSystem[] particleSystems;

        private MethodInfo calculateEffectUIDataMethod = typeof(ParticleSystem).GetMethod("CalculateEffectUIData", BindingFlags.Instance | BindingFlags.NonPublic);

        public bool isRunning = false;

        public string string_0;

        public string string_1;

        private int textureMemory;

        private int texNumber;

        private int particleSystemCount;

        private int particleNumber;

        private int drawcallPeak;

        private float overdrawRate;

        public static EffectPerformanceMonitor I = new EffectPerformanceMonitor();

        private EffectPerformanceMonitor()
        {
        }

        public void Initialize()
        {
            string_0 = null;
            string_1 = null;
            textureMemory = 0;
            texNumber = 0;
            particleSystemCount = 0;
            particleSystems = null;
            particleNumber = 0;
            drawcallPeak = 0;
            overdrawRate = 0f;
            OverdrawMonitor.Instance.InitializeRenderTexture();
            ApiCompatibilityUtils.Instance.RegisterEditorExitPlayMode(RemoveUpdate);
        }

        public void StartMonitoring(GameObject gameObject_1, ParticleSystemDrawer particleSystemDrawer1)
        {
            gameObject = gameObject_1;
            particleSystemDrawer = particleSystemDrawer1;
            particleSystems = gameObject_1.GetComponentsInChildren<ParticleSystem>(includeInactive: true);
            textureMemory = (int)CalculateMemoryUsage(out texNumber);
            particleSystemCount = GetParticleSystemCount();
            EditorApplication.update = (EditorApplication.CallbackFunction)Delegate.Combine(EditorApplication.update, new EditorApplication.CallbackFunction(UpdateParticleData));
            isRunning = true;
        }

        private int CalculateStorageMemorySize(Texture inputTexture)
        {
            int result = 0;
            object[] parameters = new object[1]
            {
                inputTexture
            };
            AssemblyTools.I.TryGetMethodResult("UnityEditor.TextureUtil", "GetStorageMemorySize", out result, parameters);
            return result;
        }

        private string ParseGameObject(GameObject selectedGameObject)
        {
            ParticleSystem[] componentsInChildren = selectedGameObject.GetComponentsInChildren<ParticleSystem>(includeInactive: true);
            string text = "";
            ParticleSystem[] array = componentsInChildren;
            foreach (ParticleSystem particleSystem in array)
            {
                string text2 = DescribeParticleSystem(particleSystem);
                if (!string.IsNullOrEmpty(text2))
                {
                    text = text + particleSystem.gameObject.name + ":" + text2 + "\n\n";
                }
            }

            return text;
        }

        private string DescribeParticleSystem(ParticleSystem particleSystem)
        {
            string text = "";
            if (particleSystem.collision.enabled)
            {
                text += "\n勾选了 Collision";
            }

            if (particleSystem.emission.enabled && particleSystem.emission.rateOverDistance.curveMultiplier != 0f)
            {
                text += "\nEmission使用了Current(非线性运算)";
            }

            if (particleSystem.externalForces.enabled)
            {
                text += "\n勾选了 External Forces";
            }

            if (particleSystem.noise.enabled)
            {
                text += "\n勾选了 Noise";
            }

            if (particleSystem.rotationBySpeed.enabled)
            {
                text += "\n勾选了 Rotation By Speed";
            }

            if (particleSystem.shape.enabled)
            {
                switch (particleSystem.shape.shapeType)
                {
                    case ParticleSystemShapeType.Mesh:
                    case ParticleSystemShapeType.MeshRenderer:
                    case ParticleSystemShapeType.BoxShell:
                        if (particleSystem.shape.arcMode == ParticleSystemShapeMultiModeValue.Random)
                        {
                            text += "\nShape的Circle-Arc使用了Random模式";
                        }

                        break;
                    case ParticleSystemShapeType.Donut:
                        if (particleSystem.shape.radiusMode == ParticleSystemShapeMultiModeValue.Random)
                        {
                            text += "\nShape的Edge-Radius使用了Random模式";
                        }

                        break;
                }
            }

            if (particleSystem.subEmitters.enabled)
            {
                text += "\n勾选了 SubEmitters";
            }

            if (particleSystem.trails.enabled)
            {
                text += "\n勾选了 Trails";
            }

            if (particleSystem.trigger.enabled)
            {
                text += "\n勾选了 Trigger";
            }

            if (particleSystem.limitVelocityOverLifetime.enabled)
            {
                text += "\n勾选了 Limit Velocity Over Lifetime";
            }

            if (particleSystem.main.gravityModifierMultiplier != 0f)
            {
                text += "\nGravityModifier 不等于0";
            }

            return text;
        }

        private int GetParticleSystemCount()
        {
            return particleSystems.Length;
        }

        public void StopRunning()
        {
            if (isRunning)
            {
                EditorApplication.update = (EditorApplication.CallbackFunction)Delegate.Remove(EditorApplication.update, new EditorApplication.CallbackFunction(UpdateParticleData));
                gameObject = null;
                particleSystems = null;
                isRunning = false;
            }
        }

        public void AssignData(ParticleEffectAssetData particleEffectAssetData0)
        {
            particleEffectAssetData0.texMemory = textureMemory;
            particleEffectAssetData0.texNumber = texNumber;
            particleEffectAssetData0.psCompNumber = particleSystemCount;
            particleEffectAssetData0.particleNumber = particleNumber;
            particleEffectAssetData0.drawcallPeak = drawcallPeak;
            particleEffectAssetData0.overdrawRate = overdrawRate;
            particleEffectAssetData0.isInitialized = true;
        }

        private void RemoveUpdate()
        {
            EditorApplication.update = (EditorApplication.CallbackFunction)Delegate.Remove(EditorApplication.update, new EditorApplication.CallbackFunction(UpdateParticleData));
            OverdrawMonitor.Instance.RemoveLastFeature();
        }

        private void UpdateParticleData()
        {
            if (particleSystemDrawer.boundsAssigned)
            {
                CalculateParticleMetrics();
                OverdrawMonitor.Instance.RenderOverdraw();
                CalculateAverageOverdrawRate();
                CalculateOnlyParticleEffectDrawCall();
            }
        }

        private void CalculateParticleMetrics()
        {
            if (particleSystems != null)
            {
                int num = 0;
                ParticleSystem[] array = particleSystems;
                foreach (ParticleSystem obj in array)
                {
                    int num2 = 0;
                    object[] array2 = new object[3]
                    {
                        0,
                        0f,
                        float.PositiveInfinity
                    };
                    calculateEffectUIDataMethod.Invoke(obj, array2);
                    num2 = (int)array2[0];
                    num += num2;
                }

                if (particleNumber < num)
                {
                    particleNumber = num;
                }
            }
        }

        private void CalculateAverageOverdrawRate()
        {
            overdrawRate = OverdrawMonitor.Instance.GetFrameInfoCollector().GetPixRate();
        }

        private void CalculateOnlyParticleEffectDrawCall()
        {
            int num = UnityStats.batches / 2;
            if (drawcallPeak < num)
            {
                drawcallPeak = num;
            }
        }

        private float CalculateMemoryUsage(out int textureCount)
        {
            List<Texture> list = new List<Texture>();
            textureCount = 0;
            float num = 0f;
            ParticleSystemRenderer[] componentsInChildren = gameObject.GetComponentsInChildren<ParticleSystemRenderer>(includeInactive: true);
            foreach (ParticleSystemRenderer particleSystemRenderer in componentsInChildren)
            {
                if (!(particleSystemRenderer.sharedMaterial != null))
                {
                    continue;
                }

                try
                {
                    MaterialProperty[] array = MaterialAssetData.TexturePropertiesInMaterial(particleSystemRenderer.sharedMaterial);
                    for (int j = 0; j < array.Length; j++)
                    {
                        Texture textureValue = array[j].textureValue;
                        if (textureValue != null && !list.Contains(textureValue))
                        {
                            list.Add(textureValue);
                            textureCount++;
                            int num2 = CalculateStorageMemorySize(textureValue);
                            num += (float)num2;
                        }
                    }
                }
                catch (Exception ex)
                {
                    ScanLog.Instance.LogInfo(ProjScan.Modules.Module.Effects_Play_Check, ScanLog.Stage.s3, "GetRuntimeMemorySizeAndTexCnt", ex.Message + "\n" + ex.StackTrace);
                }
            }

            return num / 1024f;
        }
    }
}